/*
 * PBBxmlGetter.java
 *
 * Created on October 10, 2007, 3:15 PM
 * Serves exactly one purpose - to download xml data from the GNF webserver and store it locally as a file.
 *
 *
 *Copyright 2007-2008 Jon W Huss III

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 *
 */

package proteinboxbot;

import java.io.*;
import java.net.*;
import java.util.*;
import proteinboxbot.*;

/**
 *
 * @author Jon Huss
 */
public class PBBxmlGetter {
    
    public static final String tempFile = "PBB_temp_19553ea33959fbb.tmp";
    //old location...
    //public static final String geneReportUrl = "http://biogps.gnf.org/services/GeneReport.aspx?gene_id=";
    
    //new Location...
    public static final String geneReportUrl = "http://api.biogps.gnf.org/Genes/GetGenericReport.aspx?templateId=0&gene_id=";
    private String rootDirectory;
    
    /** Creates a new instance of PBBxmlGetter */
    public PBBxmlGetter(String rootDir) {
        rootDirectory = rootDir;
    }
    
    public String getXmlFilename(){
        return this.rootDirectory + this.tempFile;
    }
    
    //http://biogps.gnf.org/services/GeneReport.aspx?gene_id=id1+id2+id3
    
    public String getXmlData(String[] ids) {
        if (ids.length < 1) {
            System.out.println("Error: No GeneIDs found.");
            return null;
        }
        String page = geneReportUrl + ids[0];
        for (int i = 1; i < ids.length; i++){
            page +="+" + ids[i];
        }
        
        //it has become necessary to output our file and download at the same time..
        String filename = this.rootDirectory + this.tempFile;
        boolean xmlResult = downloadXmlPage(page, filename);
        if (xmlResult == false) {
            return null;
        }
//        if (xmlData.length() < 200) {
//            //There just isn't enough data for this to be correct. We will return null.
//            return null;
//        }
        
//        //Now we have our XML data - we need to dump it to a file...
//        String filename = this.rootDirectory + this.tempFile;
//        try {
//
//            dumpDataToFile(filename,xmlData);
//
//        } catch (IOException ex) {
//            //if there is any sort of error, we'll just return null
//            System.out.println("Error while writing to temp file.");
//            return null;
//        }
//
//        //if we get here, everything worked great.
        return filename;
        
    }
    
    private static final void dumpDataToFile(String fileName, String data) throws IOException {
        File out;
        out = new File(fileName);
        if (out.exists()){
            out.delete();
        }
        File parent = new File(out.getParent());
        if (parent != null){
            parent.mkdirs();
        }
        out.createNewFile();
        if (out.canWrite()){
            FileWriter fw = new FileWriter(out);
            fw.write(data);
        }
        
    }
    
    
    public boolean downloadXmlPage(String page, String fileName){
        //wraps for error catching.
        boolean clear = false;
        int tries = 0;
        while (!clear){
            
            try {
                System.out.println("Downloading xml data...");
                File out;
                out = new File(fileName);
                if (out.exists()){
                    out.delete();
                }
                File parent = new File(out.getParent());
                if (parent != null){
                    parent.mkdirs();
                }
                out.createNewFile();
                if (out.canWrite()){
                    
                    
                    boolean data = downloadXmlPageH(page,out);
                    return data;
                }
            } catch(Exception e) {
                System.out.println("Entrez: Encountered Error while Downloading:");
                System.out.println(e.getMessage());
                if (tries < 3){
                    System.out.println("Trying "+ (3 - tries) + " more time(s) in 10 seconds...");
                    this.updateWait(10000);
                    this.allowComm();
                    tries++;
                    continue;
                    
                } else {
                    System.out.println("3 tries failed; Requiring User Input:");
                    tries = 0;
                }
                try {
                    BufferedReader inputLine = new BufferedReader(new InputStreamReader(System.in));
                    System.out.println("Try Again? (y/n)");
                    System.out.flush();
                    String input = inputLine.readLine();
                    //input = "y";
                    if (input.compareToIgnoreCase("y") == 0){
                        clear= false;
                    }else {
                        clear = true;
                        //throw new PBBWikiException("User Aborted Download due to error.",e);
                        return false;
                    }
                    
                } catch (IOException ex) {
                    return false;
                    //throw new PBBWikiException("Unrecoverable IO Error.",ex);
                    //System.out.println("Unrecoverable IO Error.");
                    //ex.printStackTrace();
                    //System.exit(1);
                }
            }
            
        }
        //throw new PBBWikiException("Unknown Download Error.");
        return false;
    }
    
    //Helper method for downloadPdbImage
    //return true iff it has downloaded more than 200 characters.
    private boolean downloadXmlPageH(String page, File out) throws Exception{
        //Returns the data of the indicated page. It is found in the wpTextbox1 area.
        String lineSep = System.getProperty("line.separator");
        //page = encode(page);
        URL xmlURL;
        URLConnection xmlConn;
        
        xmlURL = new URL(page);
        //glblLog.addEntry("SYSTEM","ENTREZCOMM","Downloading File:"+ entURL.toString(),PBBLogging.logs.SY);
        
        xmlConn = xmlURL.openConnection();
        //editConn.setRequestProperty("Cookie", this.getCookieData());
        //editConn.getContent();
        xmlConn.getContent();
        String input = "";
        BufferedReader xmlBR = new BufferedReader(new InputStreamReader(xmlConn.getInputStream(),"UTF-8"));
        
        //BufferedWriter bw = new BufferedWriter(new FileWriter(destination));
        String inLine = "";
        FileWriter fw = new FileWriter(out);
        //fw.write(data);
        int tmpint = xmlConn.getContentLength();
        if (tmpint > 0) {
            System.out.println("Downloading approximately " + tmpint + " characters of data.");
            System.out.flush();
        }
        
        double tmpCount = 0;
        boolean result = false;
        while ( (inLine = xmlBR.readLine()) != null) {
            if (inLine.indexOf("<?xml") != -1){
                //need to skip the encoding line
                continue;
            }
            input += inLine + lineSep;
            tmpCount = tmpCount + inLine.length();
            if (input.length() > 200){
                result = true;
                fw.write(input);
                input = "";
            }
            
        }
        System.out.println("Downloaded " + tmpCount + " Characters.");
        if (input.length() > 0) {
            fw.write(input);
        }
        fw.flush();
        fw.close();
        return result;
        
    }
    private Date nextComm;
    private void updateWait(int wait){
        Date now = new Date();
        nextComm = new Date(now.getTime() + wait);
        //DEBUG
        //System.out.println("NextComm = " + nextComm.getTime());
        //System.out.println("Now = " + now.getTime());
        //System.out.println("Difference = " + (nextComm.getTime() - now.getTime())+ " should be ~" + wait);
        
        
        
    }
    private void allowComm() {
        //this function makes the bot wait until it is allowed to perform the next communication with Wiki.
        Date now = new Date();
        
        long wait = nextComm.getTime() - now.getTime();
        //System.out.println("Wait = " + wait);
        double waitTime = ((double)wait)/1000;
        if (wait > 0) {
            System.out.println("Waiting " + waitTime + " seconds for server cooldown.");
            System.out.flush();
            long left = wait;
            while( left > 10){
                System.out.print(".");
                System.out.print(" ");
                System.out.flush();
                try {
                    if( left > 1000){
                        Thread.currentThread().sleep(1000);
                        left = left - 1000;
                    }else {
                        Thread.currentThread().sleep(left);
                        left = 0;
                        
                    }
                } catch (InterruptedException ex) {
                    System.out.println("Interrupted While Sleeping. Non-hazardous Error (ignored).");
                    //ex.printStackTrace();
                }
                
                
            }
            Date time2 = new Date();
            long actWait = time2.getTime() - now.getTime();
            System.out.println(" ("+ actWait + " milliseconds.)");
            //log.addEntry("SYSTEM","SLEPT","Waited " + actWait + " milliseconds for Server Cooldown.",PBBLogging.logs.SY);
            
        }
        return;
        
    }
    
}
